//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//
// (C) Copyright 2006 Marvell International Ltd.
// All Rights Reserved
//
//------------------------------------------------------------------------------
//
//  File:  init.c
//
//  Marvell Littleton board initialization code.
//
#include <bsp.h>
#include "xllp_lcd_plat.h"
#include "monahans_base_regs.h"
#include "xllp_defs.h"
#include "xllp_clkmgr.h"


#include <args.h>
#include <ioctl_cfg.h>

#include "pmic_power.h"
#include "ISRAM.h"

// External function prototypes.
//
extern void TURN_ON_BTB(void);
extern void InitDebugSerial(UINT32 DbgSerPhysAddr, BOOL fUsePhysical);

// A home for miscellaneous actions that must be performed after Sleep
//  reset (resume) as well as on power up.
// Defined in debug.c because of linker reasons in other modules.
// Post-sleep execution occurs in pmgr.c\PmgrOsResumeOptionalFn()
extern void OEMExecuteAfterAllResets(void);

extern BOOL OALInitEBootCfg(void);

// Function pointers for Saving/Restoring CoProc Register
extern void (* pOEMInitCoProcRegisterSavedArea) (LPBYTE pArea);
extern void (* pOEMRestoreCoProcRegister) (LPBYTE);
extern void (* pOEMSaveCoProcRegister)(LPBYTE);
extern void (*pPlatformPreSuspend)();

// Saving/Restoring CoProc Register Prototypes
void OEMInitCoProcRegisterSavedArea(LPBYTE pArea);
void OEMSaveCoProcRegister( LPBYTE pArea );
void OEMRestoreCoProcRegister( LPBYTE pArea);
void PlatformPreSuspend();

// Function to enable the CP0 & CP1 access bits in CP15
extern void Xllp_Set_CoProc_Access(void);

// Prototypes for Assembly routines used for saving/restoring CoProc Registers
extern void Xllp_Save_WMMX_Regs(LPBYTE pArea);
extern void Xllp_Restore_WMMX_Regs(LPBYTE pArea);

extern DWORD cbNKCoProcRegSize;
extern DWORD fNKSaveCoProcReg;

#ifdef USING_XSCALEBROWSER
static BYTE TraceBuffer[20][268]; // space for 20 captures
#endif


// External global variables.
//
extern DWORD dwNKDrWatsonSize;
extern DWORD CEProcessorType;   // From nkarm.h in the private tree

// External platform variables.
extern LPCWSTR g_oalIoCtlPlatformManufacturer;
extern LPCWSTR g_oalIoCtlPlatformName;

// Cache-related variables.
//
// NOTE: We dont need ZBANK with the Manzano core.
//  
//
#define ZBANK_BASE_C_VIRTUAL        0x0      
DWORD CacheBufferFlag;  // NOTE: this needn't be a const variable and OEMCacheRangeFlush won't be called before KernelRe locate.
const LPVOID gpvCacheFlushBaseMemoryAddress = (LPVOID)ZBANK_BASE_C_VIRTUAL;

BOOL L2CacheEnable=FALSE;

BSP_ARGS *g_pBSPArgs;
void lcd_clock_update_init();

#ifdef PRODUCT_SERIAL_ENABLED
BOOL g_bDebugSerialEnable = FALSE;
#else
BOOL g_bDebugSerialEnable = TRUE;
#endif

//------------------------------------------------------------------------------
//
//  Function:  OEMInit
//
//  This is Windows CE OAL initialization function. It is called from kernel
//  after basic initialization is made.
//
void OEMInit()
{
    volatile XLLP_CLKMGR_T *pCLKReg = (XLLP_CLKMGR_T *)OALPAtoVA(MONAHANS_BASE_REG_PA_CLKMGR, FALSE);

    OALMSG(1, (L"+OEMInit\r\n"));

    //OALLogSetZones(0xFFFFFFFF);         // all of them for now

    //
    // Expose the Littleton processor type.
    // Expose the Littleton processor type.
    //the 'true' processory type is PROCESSOR_ARM920 as Xscale is based on ARM920 core
    //but most of the ISVs expect this value to be PROCESSOR_STRONGARM and their apps fail
    //to install if it is otherwise.
    CEProcessorType = PROCESSOR_STRONGARM;

    // Enable the branch-target buffer.
    //
	TURN_ON_BTB();

	NKForceCleanBoot();
	
	g_pBSPArgs = (BSP_ARGS *)IMAGE_SHARE_ARGS_UA_START;
	
	if(OALArgsQuery(BSP_ARGS_QUERY_L2CACHE))
	{
		L2CacheEnable=*(BOOL*)OALArgsQuery(BSP_ARGS_QUERY_L2CACHE);
	}


    // Set memory size for DrWatson kernel support.
    //
    dwNKDrWatsonSize = 128 * 1024;

    // Intialize optional kernel functions.
    //
    pOEMIsProcessorFeaturePresent = OALIsProcessorFeaturePresent;

    #if defined(USING_COPROCSUPPORT) || defined(USING_XSCALEBROWSER)
    // Setup Saving & Restoring of CoProcessor Registers

    //Assembly routine to turn on CP0 access bit located in cpregXsc1.s
    // NOTE:  If access bits are not enabled, when saving/restoring/accessing
    //  CP0, will get an undefined exception!!!!
    // Note:  The save/restore functions assume bit is enabled, a user can
    //  create an IOCTL that can disable it and cause undefined exceptions!!

    // NSC: commented out
    // ENABLE_COPROC_ACCESS();

    //Set the buffer size to 8 bytes, to accommodate 16X64-bits + 6X32-bits (with alignment)
    cbNKCoProcRegSize = 156;  //Add 4 bytes to save off flags (keeping alignment)
    fNKSaveCoProcReg = 1;

    // Now setup the callback pointers
    pOEMInitCoProcRegisterSavedArea = OEMInitCoProcRegisterSavedArea;
    pOEMRestoreCoProcRegister = OEMRestoreCoProcRegister;
    pOEMSaveCoProcRegister = OEMSaveCoProcRegister;
    pPlatformPreSuspend = PlatformPreSuspend;

#endif //USING_COPROCSUPPORT

#ifdef USING_XSCALEBROWSER
    XSCBwrInitExecutionTrace(TraceBuffer, sizeof(TraceBuffer));
#endif //USING_XSCALEBROWSER

    // Initialize interrupts.
    //
    if (!OALIntrInit())
    {
        OALMSG(OAL_ERROR, (
                          L"ERROR: OEMInit: failed to initialize interrupts.\r\n"
                          ));
    }

    // Initialize system clock.
    //
    OALTimerInit();
    
    lcd_clock_update_init();

    // Initilize the globals used in IOCTL_HAL_DEVICE_INFO handler
    g_oalIoCtlPlatformManufacturer = IOCTL_PLATFORM_MANUFACTURER;
    g_oalIoCtlPlatformName = IOCTL_PLATFORM_NAME;

    RegisterPowerDomainFunctions(EnableSRAMPowerDomain, DisableSRAMPowerDomain);
    DisableSRAM();

    // disable boot rom clock
    XllpClockEnable((P_XLLP_CLKMGR_T)pCLKReg, XLLP_CLK_BOOT, XLLP_FALSE);

    // Initialize the KITL connection if required.
    //
    OALKitlStart();

    OALMSG(1, (L"-OEMInit\r\n"));
}

	
	
VOID OALStall(UINT32 microSec)
{
    volatile PPXA_OST_REG pOSTRegs = NULL;

    pOSTRegs = (PPXA_OST_REG)OALPAtoVA(MONAHANS_BASE_REG_PA_OST, FALSE);

    XllpOstDelayMicroSeconds(pOSTRegs, microSec);
}

//
// ASM routine
//
//extern void ADJUST_PC(void);

VOID OEMInitDebugSerial(void)
{

    //UINT32 *pDbgSerPhysAddr = (UINT32*) OALArgsQuery(BSP_ARGS_QUERY_DBGSERIAL);  // returns a void *, the physical address of the port.
    volatile UINT32 *pDbgSerVirtAddr = (volatile UINT32 *)0xA8100000;

    //*pDbgSerVirtAddr = 0x47;

    /*
    case BSP_ARGS_QUERY_DBGSERIAL:
        if ((pArgs->dbgSerPhysAddr != MONAHANS_BASE_REG_PA_BTUART) && (pArgs->dbgSerPhysAddr != MONAHANS_BASE_REG_PA_FFUART))
        {
            pArgs->dbgSerPhysAddr = MONAHANS_BASE_REG_PA_FFUART;
        }
        pData = &pArgs->dbgSerPhysAddr;            <<-- returns the address of where the address is stored.
        break;
    */    

    g_pBSPArgs = (BSP_ARGS *)IMAGE_SHARE_ARGS_UA_START;

    if (
        g_pBSPArgs->header.signature  != OAL_ARGS_SIGNATURE ||
        g_pBSPArgs->header.oalVersion != OAL_ARGS_VERSION   ||
        g_pBSPArgs->header.bspVersion != BSP_ARGS_VERSION   ||
        g_pBSPArgs->argsLength != sizeof (BSP_ARGS)    )
    {
        InitDebugSerial((UINT32) MONAHANS_BASE_REG_PA_SIRUART, FALSE);         // hardcode the phy for bring up.
        g_bDebugSerialEnable = TRUE;    // in order to output the message
        OALMSGS(1, (L"Eboot and OS version mismatch!!! \r\nPlease erase the flash, burn bootimage and OS of same version, then try again.\r\nHalt here!\r\n"));
        while (1);
    }

    if(g_pBSPArgs->STUARTUsage&BSP_ARGS_STUART_DEBUG_SERIAL)
         g_bDebugSerialEnable = TRUE;
    else
         g_bDebugSerialEnable = FALSE;


    // DEBUG: no args right now... hardcode the serial address
    //UINT32 *pDbgSerPhysAddr = (UINT32 *) 0xA8100000;  // uc va ffuart base = 0xA8100000
    //UINT32 *pDbgSerPhysAddr = (UINT32 *) 0x40100000;  // PHY ffuart base = 0x40100000.  Assumes the PHY and will do a lookup for the virtual.

    //OALMSG(1, (L"+OEMInitDebugSerial\r\n"));
    // == NKDbgPrintfW

    //if (pDbgSerPhysAddr)
    //{
        //InitDebugSerial(*pDbgSerPhysAddr);
     InitDebugSerial((UINT32) MONAHANS_BASE_REG_PA_SIRUART, FALSE);         // hardcode the phy for bring up.

	 //*pDbgSerVirtAddr = 0x48;

    //}
}

//------------------------------------------------------------------------------


/* ************************************************************************* */
/*
OEMInitCoProcRegisterSavedArea

   This function sets up the memory area allocated for use in saving/restoring
   CoProcessor registers.  This function is called for every thread created.

Parameters
   Pointer to a memory are defined above by the value of cbNkCoProcRegSize

Return Value
   None
*/
/* ************************************************************************* */
void OEMInitCoProcRegisterSavedArea(LPBYTE pArea)
{
    // Set initial state of CoProc Reg Area (which will in turn be the Register value) here
    memset(pArea,0,156);

}


/* ************************************************************************* */
/*
OEMSaveCoProcRegister

   This function calls the Assembly routines to read the contents of the
   CoProcessor register, storing it in pArea.  It is only called when both
   cbNkCoProcRegSize and fNKSaveCoProcReg are fo non-zero values.  This
   function is called every time a thread is to be switched out, so it
   adds to the overall worst-case time of thread switches!

Parameters
   Pointer to a memory are defined above by the value of cbNkCoProcRegSize

Return Value
   None
*/
/* ************************************************************************* */
void OEMSaveCoProcRegister( LPBYTE pArea )
{
#ifdef USING_XSCALEBROWSER
    if (XSCBwrThreadID == GetCurrentThreadId() )
    {
        XSCBwrExecutionTraceOff(0);
        XSCBwrSaveThreadContextArea.ThreadId = XSCBwrThreadID;
        XSCBwrSaveThreadContextArea.ContextPtr = (DWORD) pArea;
        Xllp_Save_WMMX_Regs((LPBYTE)
                            &XSCBwrSaveThreadContextArea.Context_Area[0] );
        return;
    }
#endif // USING_XSCALEBROWSER
    Xllp_Save_WMMX_Regs( pArea );
}


/* ************************************************************************* */
/*
OEMRestoreCoProcRegister

   This function calls the Assembly routines to set the contents of the
   CoProcessor register back to what was stored in pArea.  It is only called
   when both cbNkCoProcRegSize and fNKSaveCoProcReg are fo non-zero values.
   This function is called every time a thread is to be switched in, so it
   adds to the overall worst-case time of thread switches!

Parameters
   Pointer to a memory are defined above by the value of cbNkCoProcRegSize

Return Value
   None
*/
/* ************************************************************************* */
void OEMRestoreCoProcRegister( LPBYTE pArea)
{
#ifdef USING_XSCALEBROWSER
    if (XSCBwrSaveThreadContextArea.ContextPtr == (DWORD) pArea )
    {
        Xllp_Restore_WMMX_Regs( (LPBYTE)&XSCBwrSaveThreadContextArea.Context_Area[0] );
        if ( XSCBwrThreadID == (DWORD) INVALID_HANDLE_VALUE )
        {
            XSCBwrSaveThreadContextArea.ContextPtr = 0;
        }
        else
        {
            XSCBwrExecutionTraceOn(0);
        }
        return;
    }
#endif //USING_XSCALEBROWSER
    Xllp_Restore_WMMX_Regs( pArea );
}





//
// void OEMExecuteAfterAllResets(void);
//   The purpose of this function is to provide a single location for operations that
//   must be performed after Sleep reset as well as at power-on, but which do not belong
//   to a particular driver and are not ideal for low-level assembly startup code.
//
//  It is called from OEMInit() at poweron and from PmgrOsSuspendOptionalFn() after Sleep.
//
// A natural home for this function would be cfwBvd1.c, but that causes linking problemms
//  in at least one driver.

void OEMExecuteAfterAllResets(void)
{

} // OEMExecuteAfterAllResets()


//
//  Called from OEMPowerOff() just before we suspend.
// This is after the OS has handed control off to the OEM, so we have no services available.
// 
void PlatformPreSuspend()
{

    volatile UINT32 *pPCFR = (volatile UINT32 *)OALPAtoVA(0x40F5000C, FALSE);

    // Set L1_dis to disable the L1 linear regulator in sleep.  
    //  It is automatically shut down upon S2 entry.
    //
    *pPCFR = (*pPCFR & 0xFFF02107) | 0x2000;        

    // Enable SL_ROD, which will supress nRESET_OUT from being altered when entering/exiting S2.
    //  This is done to ensure that the GPIO expanders and other components do not lose state.
    //
    *pPCFR = (*pPCFR & 0xFFF02107) | (1<<1);

}

 
